package com.Jshop.order.service;

import com.Jshop.common.pojo.PageResult;
import com.Jshop.common.utils.JsonUtils;
import com.Jshop.order.client.SkuFeign;
import com.Jshop.order.client.UserFeign;
import com.Jshop.order.entity.UserInfo;
import com.Jshop.order.interceptor.LoginInterceptor;
import com.Jshop.order.mapper.OrderDetailMapper;
import com.Jshop.order.mapper.OrderMapper;
import com.Jshop.order.mapper.OrderStatusMapper;
import com.Jshop.order.mapper.SeckillGoodsMapper;
import com.Jshop.order.pojo.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.item.pojo.Sku;
//import io.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class OrderService {

    @Resource
    private IdWorker idWorker;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderDetailMapper detailMapper;

    @Resource
    private OrderStatusMapper statusMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    //cart redis
    static final String KEY_PREFIX = "Jshop:cart:uid:";

    //ItemFeign
    @Resource
    private SkuFeign skuFeign;

    //UserFeign
    @Resource
    private UserFeign userFeign;

    //MQ
    @Resource
    private RabbitTemplate rabbitmq;


    @Resource
    private SeckillGoodsMapper seckillGoodsMapper;


//    @Transactional
//    @GlobalTransactional
    public Long createOrder(Order order) {
        //get user
        UserInfo user = LoginInterceptor.getLoginUser();
        //价格浮动 由于支付服务没有成熟 pass
        //生成orderId
        Long orderId = idWorker.nextId();
        //异步 延时消息队列发送
        rabbitmq.convertAndSend("directDelayExchange", "orderDelayQueueKey", (Object)orderId.toString(), new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration("30000");
                System.out.println(message + "已发送");
                return message;
            }
    });
        // 初始化数据
        order.setBuyerNick(user.getUsername());
        order.setBuyerRate(false);
        order.setCreateTime(LocalDateTime.now());
        order.setOrderId(orderId);
        order.setUserId(user.getId());
        // 保存数据
        this.orderMapper.insertSelective(order);
        // 保存订单状态
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setOrderId(orderId);
        orderStatus.setCreateTime(order.getCreateTime());
        orderStatus.setStatus(1);// 初始状态为未付款
        this.statusMapper.insertSelective(orderStatus);
        // 订单详情中添加orderId
        order.getOrderDetails().forEach(od -> od.setOrderId(orderId));
        // 保存订单详情,使用批量插入功能
        this.detailMapper.insertList(order.getOrderDetails());
        //分布式事务 >>  Seata
        //用户积分累加 分布式事务2
        userFeign.addPoint(user.getUsername());
        //库存递减 分布式事务1
        Map<String, Integer> skuDecrMap = order.getOrderDetails().stream().collect(Collectors.toMap(key -> key.getSkuId().toString() , value -> value.getNum()));
        skuFeign.decrementStock(skuDecrMap);
        //模拟出现异常
        //如果无分布式事务机制 用户积分会+1
        //如果有分布式事务 用户积分会回滚
//        int i = 10/0;
        // TODO: 2021/11/9 保证事务？ 购物车数据落MySQL 这里MYSQL之间保证事务 购物车MYSQL和Redis的一致性由Cannal进行保证
        // 删除购物车相关列表项
        //hash redis
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + user.getId());;
        //order contains sku ids
        List<Long> skuIds = order.getOrderDetails().stream().map(OrderDetail::getSkuId).collect(Collectors.toList());
        for (Long skuId : skuIds) {
            hashOps.delete(String.valueOf(skuId));
        }
        logger.debug("生成订单，订单编号：{}，用户id：{}", orderId, user.getId());
        return orderId;
    }


    public Order queryById(Long id) {
        // 查询订单
        Order order = this.orderMapper.selectByPrimaryKey(id);

        // 查询订单详情
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(id);
        List<OrderDetail> details = this.detailMapper.select(detail);
        order.setOrderDetails(details);

        // 查询订单状态
        OrderStatus status = this.statusMapper.selectByPrimaryKey(order.getOrderId());
        order.setStatus(status.getStatus());
        return order;
    }

    public PageResult<Order> queryUserOrderList(Integer page, Integer rows, Integer status) {
        try {
            // 分页
            PageHelper.startPage(page, rows);
            // 获取登录用户
            UserInfo user = LoginInterceptor.getLoginUser();
            // 创建查询条件
            Page<Order> pageInfo = (Page<Order>) this.orderMapper.queryOrderList(user.getId(), status);

            return new PageResult<>(pageInfo.getTotal(), pageInfo);
        } catch (Exception e) {
            logger.error("查询订单出错", e);
            return null;
        }
    }

    @Transactional
    public Boolean updateStatus(Long id, Integer status) {
        OrderStatus record = new OrderStatus();
        record.setOrderId(id);
        record.setStatus(status);
        // 根据状态判断要修改的时间
        switch (status) {
            case 2:
                record.setPaymentTime(LocalDateTime.now());// 付款
                break;
            case 3:
                record.setConsignTime(LocalDateTime.now());// 发货
                break;
            case 4:
                record.setEndTime(LocalDateTime.now());// 确认收获，订单结束
                break;
            case 5:
                record.setCloseTime(LocalDateTime.now());// 交易失败，订单关闭
                break;
            case 6:
                record.setCommentTime(LocalDateTime.now());// 评价时间
                break;
            default:
                return null;
        }
        int count = this.statusMapper.updateByPrimaryKeySelective(record);
        return count == 1; // todo mp 注意点
    }


    public Integer queryOrderStatus(Long orderId) {
        OrderStatus od = new OrderStatus();
        od.setOrderId(orderId);
        OrderStatus orderStatus = this.statusMapper.selectOne(od);
        if (orderStatus == null){
            return null;
        }
        return orderStatus.getStatus();
    }


}
